package com.minivision.fdiot.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
//import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.crypto.codec.Utf8;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.minivision.fdiot.annotation.NoAuth;
import com.minivision.fdiot.common.CommonConstants;
import com.minivision.fdiot.entity.AppInfo;
import com.minivision.fdiot.exception.ErrorType;
import com.minivision.fdiot.exception.FacePlatException;
import com.minivision.fdiot.repository.mysql.AppRepository;

import lombok.extern.slf4j.Slf4j;

/**
 * API鉴权拦截器
 * @author hughzhao
 * @2018年3月1日
 */
@Component
@Slf4j
public class ApiAuthInterceptor extends HandlerInterceptorAdapter {
  
  @Autowired
  private AppRepository appRepo;
  /*@Autowired
  private Md5PasswordEncoder md5Encoder;*/
  //token有效期
  @Value("${api.token.timeout}")
  private long tokenTimeout;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    if (handlerMethod.hasMethodAnnotation(NoAuth.class)) {
      return true;
    }
    String authToken = request.getHeader(CommonConstants.AUTH_HEADER);
    String appKey = request.getParameter("appKey");
    String timestamp = request.getParameter("timestamp");
    if(!access(appKey, authToken, timestamp)){
      throw new FacePlatException(ErrorType.AUTHORITY_ERROR);
    }
    return true;
  }

  private boolean access(String appKey, String authToken, String timestamp) {
    if (!StringUtils.hasText(appKey) || !StringUtils.hasText(authToken) || !StringUtils.hasText(timestamp)) {
      log.error("required param is absent, Token:{}, appKey:{}, timestamp:{}", authToken, appKey, timestamp);
      return false;
    }
    try {
      long time = Long.valueOf(timestamp);
      if (System.currentTimeMillis() - time > tokenTimeout) {
        log.error("token timeout: timestamp={}", timestamp);
        return false;
      }
    } catch (Exception e) {
      log.error("invalid timestamp:" + timestamp, e);
      return false;
    }
    AppInfo appInfo = appRepo.findByAppKey(appKey);
    if (appInfo == null) {
      log.error("app[{}] not exists", appKey);
      return false;
    }
    String appSecret = appInfo.getAppSecret();
    if (!StringUtils.hasText(appSecret)) {
      log.error("no appSecret for app[{}]", appKey);
      return false;
    }
    //md5Encoder.encodePassword(appKey, appSecret + ":" + timestamp)
    if (!authToken.equalsIgnoreCase(DigestUtils.md5DigestAsHex(Utf8.encode(appKey + "{" + appSecret + ":" + timestamp + "}")))) {
      log.error("invalid token");
      return false;
    }
    return true;
  }

  public static void main(String[] args) throws Exception {
    long timestamp = System.currentTimeMillis();
    System.out.println("timestamp:" + timestamp);
    
    String appSecret = "xskj2017";
    String tokenSecret = appSecret + ":" + timestamp;
    
    /*Md5PasswordEncoder encoder = new Md5PasswordEncoder();
    String appName = "智慧商圈";
    
    String appKey = encoder.encodePassword(appName, appSecret);
    System.out.println(encoder.encodePassword(appKey, tokenSecret));
    System.out.println(encoder.encodePassword(appKey, tokenSecret));
    System.out.println(encoder.encodePassword(appKey, tokenSecret));
    System.out.println(DigestUtils.md5DigestAsHex(Utf8.encode(appKey + "{" + tokenSecret + "}")));
    System.out.println(DigestUtils.md5DigestAsHex((appKey + "{" + tokenSecret + "}").getBytes("UTF-8")));*/
    
    String appKey = "9a70cf8670b6ef0300927e92df7a16be";
    System.out.println(DigestUtils.md5DigestAsHex(Utf8.encode(appKey + "{" + appSecret + ":" + timestamp + "}")));
    System.out.println(DigestUtils.md5DigestAsHex(Utf8.encode(appKey + "{" + tokenSecret + "}")));
    System.out.println(org.apache.commons.codec.digest.DigestUtils.md5Hex((appKey + "{" + tokenSecret + "}").getBytes("UTF-8")));
  }

}
